package com.aloda.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.aloda.annotation.RateLimit;
import com.aloda.cache.RedisUtils;
import com.aloda.constant.*;
import com.aloda.context.AdminBaseContext;
import com.aloda.context.UserBaseContext;
import com.aloda.dto.app.AppAddDTO;
import com.aloda.dto.app.AppEditDTO;
import com.aloda.dto.app.AppReviewDTO;
import com.aloda.dto.user.UserSafetyDTO;
import com.aloda.entity.*;
import com.aloda.enums.*;
import com.aloda.exception.BaseException;
import com.aloda.exception.WarnException;
import com.aloda.mapper.*;
import com.aloda.query.AppPageDTO;
import com.aloda.query.AppScrollingPageDTO;
import com.aloda.query.PageQuery;
import com.aloda.query.SearchPageDTO;
import com.aloda.result.PageResult;
import com.aloda.service.AppService;
import com.aloda.utils.CheckUtils;
import com.aloda.vo.app.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author aloda
 * @description 针对表【app(应用)】的数据库操作Service实现
 * @createDate 2025-03-05 16:27:38
 */
@Service
public class AppServiceImpl extends ServiceImpl<AppMapper, App> implements AppService {

    @Resource
    private AppMapper appMapper;

    @Resource
    private EmpMapper empMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private AppCategoryMapper appCategoryMapper;

    @Resource
    private QuestionMapper questionMapper;

    @Resource
    private ScoringResultMapper scoringResultMapper;

    @Resource
    private UserAnswerMapper userAnswerMapper;

    @Resource
    private CollectMapper collectMapper;

    @Resource
    private RedisUtils redisUtils;

    /**
     * 管理端新增应用
     *
     * @param appAddDTO
     * @return
     */
    @Override
    public long addApp(AppAddDTO appAddDTO) {
        // 1.数据格式校验
        if (!checkAddDTO(appAddDTO)) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        // 2.写入默认字段
        // 加入app分类
        AppCategory appCategory = appCategoryMapper.selectById(appAddDTO.getCategoryId());
        if (BeanUtil.isEmpty(appCategory)) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_NOT_EXIST);
        }
        Long userId = appAddDTO.getUserId();
        if (userId == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        User user = userMapper.selectById(userId);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        App app = BeanUtil.copyProperties(appAddDTO, App.class);
        app.setCategoryId(appAddDTO.getCategoryId());
        app.setAppCategory(appCategory.getCategoryName());
        app.setUserId(user.getId());
        app.setCreateUser(user.getUserAccount());
        app.setCreateTime(LocalDateTime.now());
        app.setUpdateTime(LocalDateTime.now());
        app.setReviewStatus(ReviewStatusEnum.REVIEWING.getValue());
        app.setAnalysisAuth(AppAnalysisAuthEnum.NO.getValue());
        // 3.存储数据
        appMapper.insert(app);
        // 4.返回id
        return app.getId();
    }

    /**
     * 分页查询
     *
     * @param appPageDTO
     * @return
     */
    @Override
    public PageResult<AppPageVO> pageQuery(AppPageDTO appPageDTO) {
        Page<App> page = appPageDTO.toMpPageDefaultSortByUpdateTimeDesc();
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.like(appPageDTO.getAppName() != null, App::getAppName, appPageDTO.getAppName())
                .like(appPageDTO.getCategoryName() != null, App::getAppCategory, appPageDTO.getCategoryName())
                .like(appPageDTO.getCreateUser() != null, App::getCreateUser, appPageDTO.getCreateUser())
                .like(appPageDTO.getId() !=null ,App::getId, appPageDTO.getId())
                .eq(appPageDTO.getAppType() != null, App::getAppType, appPageDTO.getAppType())
                .eq(appPageDTO.getReviewStatus() != null, App::getReviewStatus, appPageDTO.getReviewStatus())
                .between(appPageDTO.getBeginTime() != null && appPageDTO.getEndTime() != null,
                        App::getCreateTime, appPageDTO.getBeginTime(), appPageDTO.getEndTime());
        appMapper.selectPage(page, appLambdaQueryWrapper);
        return PageResult.of(page, AppPageVO.class);
    }

    /**
     * 编辑应用
     *
     * @param appEditDTO
     * @return
     */
    @Override
    public long editApp(AppEditDTO appEditDTO) {
        checkEditDTO(appEditDTO);
        // 加入app分类
        AppCategory appCategory = appCategoryMapper.selectById(appEditDTO.getCategoryId());
        if (BeanUtil.isEmpty(appCategory)) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_NOT_EXIST);
        }
        App app = BeanUtil.copyProperties(appEditDTO, App.class);
        app.setCategoryId(appEditDTO.getCategoryId());
        app.setAppCategory(appCategory.getCategoryName());
        app.setAnalysisAuth(appEditDTO.getAnalysisAuth());
        app.setUpdateTime(LocalDateTime.now());
        int i = appMapper.updateById(app);
        // 删除app对应的所有题目选项缓存
        String prefixKey = RedisConstant.APP_USER_ANSWER + app.getId().toString() + ":";
        redisUtils.deleteObjectFormCacheByPrefix(prefixKey);
        return i;
    }

    /**
     * 导出表格
     *
     * @param response
     * @param ids
     */
    @Override
    public void exportAppToExcel(HttpServletResponse response, List<Long> ids) {
        try {
            // 设置响应头
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("应用信息表", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            // 查询所有信息 如果ids为空查询所有信息，否则查询对应信息
            LambdaQueryWrapper<App> queryWrapper = new LambdaQueryWrapper<>();
            List<App> appList;
            if (ids.isEmpty()) {
                appList = appMapper.selectList(queryWrapper);
            } else {
                appList = appMapper.selectBatchIds(ids);
            }

            // 转换为导出VO
            List<AppExportVO> exportVOList = appList.stream().map(app -> {
                        AppExportVO appExportVO = BeanUtil.copyProperties(app, AppExportVO.class);
                        appExportVO.setId(app.getId().toString());
                        return appExportVO;
                    })
                    .collect(Collectors.toList());

            // 使用EasyExcel导出
            EasyExcel.write(response.getOutputStream(), AppExportVO.class)
                    .sheet("应用信息")
                    .doWrite(exportVOList);

        } catch (IOException e) {
            throw new RuntimeException(ExceptionConstant.EXPORT_EXCEL_ERROR, e);
        }
    }

    /**
     * 审核应用
     *
     * @param appReviewDTO
     */
    @Override
    public void reviewApp(AppReviewDTO appReviewDTO) {
        if (ReviewStatusEnum.getEnumByValue(appReviewDTO.getReviewStatus()) == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        App app = BeanUtil.copyProperties(appReviewDTO, App.class);
        Long currentId = AdminBaseContext.getCurrentId();
        Emp emp = empMapper.selectById(currentId);
        app.setReviewerId(currentId);
        app.setReviewerAccount(emp.getEmpAccount());
        app.setReviewMessage(appReviewDTO.getReviewMessage());
        app.setReviewStatus(appReviewDTO.getReviewStatus());
        app.setReviewTime(LocalDateTime.now());
        app.setUpdateTime(LocalDateTime.now());
        appMapper.updateById(app);
    }

    /**
     * 删除应用
     *
     * @param ids
     * @return
     */
    @Override
    public boolean deleteApp(List<Long> ids) {
        for (Long id : ids) {
            deleteAppResource(id);
        }
        return true;
    }

    /**
     * 获取首页推荐应用列表
     *
     * @return
     */
    @Override
    public List<AppCardVO> getRecommendAppList() {
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.orderByDesc(App::getUpdateTime)
                .eq(App::getReviewStatus, ReviewStatusEnum.PASS.getValue())
                .eq(App::getRecommendFlag, AppRecommendEnum.RECOMMEND.getValue());
        List<App> appList = appMapper.selectList(appLambdaQueryWrapper);
        return toAppCardVOList(appList);
    }

    /**
     * 通过id获取应用详情
     *
     * @param id
     * @return
     */
    @Override
    public AppDetailVO getAppDetailById(Long id) {
        Long currentId = UserBaseContext.getUser().getId();
        App app = appMapper.selectById(id);
        if (BeanUtil.isEmpty(app)) {
            throw new BaseException(ErrorCode.FORBIDDEN_ERROR);
        }
        // 如果应用未过审且访问者非该应用创建者本人，提示该应用未过审
        if (!app.getReviewStatus().equals(ReviewStatusEnum.PASS.getValue()) && !app.getUserId().equals(currentId)) {
            throw new BaseException(ErrorCode.FORBIDDEN_ERROR);
        }
        AppDetailVO appDetailVO = BeanUtil.copyProperties(app, AppDetailVO.class);
        User user = userMapper.selectById(app.getUserId());
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        appDetailVO.setNickname(user.getNickname());
        appDetailVO.setAvatar(user.getAvatar());
        appDetailVO.setIsCreateUser(UserBaseContext.getUser().getId().equals(app.getUserId()));
        Integer integer = collectMapper.selectIsCollect(app.getId(), currentId);
        appDetailVO.setCollectFlag(integer > 0);
        return appDetailVO;
    }

    /**
     * 滚动分页查询
     *
     * @param appScrollingPageDTO
     * @return
     */
    @Override
    public List<AppCardVO> getAppScrollingPageList(AppScrollingPageDTO appScrollingPageDTO) {
        // 1.参数校验
        Long categoryId = appScrollingPageDTO.getCategoryId();
        if (categoryId == null) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_ID_ERROR);
        }
        AppCategory appCategory = appCategoryMapper.selectById(categoryId);
        if (BeanUtil.isEmpty(appCategory)) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_NOT_EXIST);
        }
        // 2.开始滚动分页
        Page<App> appPage = new Page<>(appScrollingPageDTO.getCurrentPage(), AppScrollingPageDTO.DEFAULT_PAGE_SIZE);
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.eq(appScrollingPageDTO.getCategoryId() != null, App::getCategoryId, appScrollingPageDTO.getCategoryId())
                .eq(App::getReviewStatus, ReviewStatusEnum.PASS.getValue())
                .orderByDesc(App::getUpdateTime);
        appMapper.selectPage(appPage, appLambdaQueryWrapper);
        // 3.封装返回数据
        return toAppCardVOList(appPage.getRecords());
    }

    /**
     * 用户端新增应用
     *
     * @param appAddDTO
     * @return
     */
    @Override
    @RateLimit(limit = 2)
    public long addAppByUser(AppAddDTO appAddDTO) {
        // 1.数据格式校验
        if (!checkAddDTO(appAddDTO)) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        // 2.写入默认字段
        // 加入app分类
        AppCategory appCategory = appCategoryMapper.selectById(appAddDTO.getCategoryId());
        if (BeanUtil.isEmpty(appCategory)) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_NOT_EXIST);
        }
        UserSafetyDTO userSafetyDTO = UserBaseContext.getUser();
        App app = BeanUtil.copyProperties(appAddDTO, App.class);
        app.setCategoryId(appAddDTO.getCategoryId());
        app.setAppCategory(appCategory.getCategoryName());
        app.setUserId(userSafetyDTO.getId());
        app.setCreateUser(userSafetyDTO.getUserAccount());
        app.setCreateTime(LocalDateTime.now());
        app.setUpdateTime(LocalDateTime.now());
        app.setReviewStatus(ReviewStatusEnum.REVIEWING.getValue());
        app.setAnalysisAuth(AppAnalysisAuthEnum.NO.getValue());
        // 3.存储数据
        appMapper.insert(app);
        // 4.返回id
        return app.getId();
    }

    /**
     * 用户端编辑应用
     *
     * @param appEditDTO
     * @return
     */
    @Override
    public long editAppByUser(AppEditDTO appEditDTO) {
        // 1.校验参数
        checkEditDTO(appEditDTO);
        // 2.校验app分类
        AppCategory appCategory = appCategoryMapper.selectById(appEditDTO.getCategoryId());
        if (BeanUtil.isEmpty(appCategory)) {
            throw new BaseException(ExceptionConstant.APP_CATEGORY_NOT_EXIST);
        }
        // 3.校验编辑者是否为创建用户
        App app = appMapper.selectById(appEditDTO.getId());
        if (BeanUtil.isEmpty(app)) {
            throw new BaseException(ExceptionConstant.APP_NOT_EXIST);
        }
        UserSafetyDTO user = UserBaseContext.getUser();
        if (!app.getUserId().equals(user.getId())) {
            throw new BaseException(ErrorCode.FORBIDDEN_ERROR);
        }
        // 4.更新app内容
        BeanUtil.copyProperties(appEditDTO, app);
        app.setAppCategory(appCategory.getCategoryName());
        app.setReviewStatus(ReviewStatusEnum.REVIEWING.getValue());
        app.setUpdateTime(LocalDateTime.now());
        appMapper.updateById(app);

        // 删除app对应的所有题目选项缓存
        String prefixKey = RedisConstant.APP_USER_ANSWER + app.getId().toString() + ":";
        redisUtils.deleteObjectFormCacheByPrefix(prefixKey);
        return app.getId();
    }

    /**
     * 用户端删除应用
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public boolean deleteAppByUser(Long id) {
        // 1.id未null返回参数错误
        if (id == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.检查当前用户是否为创建用户
        App app = appMapper.selectById(id);
        if (BeanUtil.isEmpty(app)) {
            throw new BaseException(ExceptionConstant.APP_NOT_EXIST);
        }
        if (!app.getUserId().equals(UserBaseContext.getUser().getId())) {
            throw new BaseException(ErrorCode.FORBIDDEN_ERROR);
        }
        return deleteAppResource(app.getId());
    }

    /**
     * 用户端设置应用分析查看权限
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public int setAnalysisAuth(Long id, Integer status) {
        if (id == null || status == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        if (AppAnalysisAuthEnum.getEnumByValue(status) == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        App app = appMapper.selectById(id);
        if (BeanUtil.isEmpty(app)) {
            throw new BaseException(ExceptionConstant.APP_NOT_EXIST);
        }
        if (!app.getUserId().equals(UserBaseContext.getUser().getId())) {
            throw new BaseException(ErrorCode.FORBIDDEN_ERROR);
        }
        app.setAnalysisAuth(status);
        app.setUpdateTime(LocalDateTime.now());
        return appMapper.updateById(app);
    }

    /**
     * 根据关键词搜索应用
     *
     * @param searchPageDTO
     * @return
     */
    @Override
    public List<AppCardVO> searchApp(SearchPageDTO searchPageDTO) {
        // 1.校验参数
        String searchValue = searchPageDTO.getSearchValue();
        if (StrUtil.isBlank(searchValue)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.开始滚动分页
        Page<App> appPage = new Page<>(searchPageDTO.getCurrentPage(), SearchPageDTO.DEFAULT_PAGE_SIZE);
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.like(App::getAppName, searchValue)
                .eq(App::getReviewStatus, ReviewStatusEnum.PASS.getValue())
                .orderByDesc(App::getUpdateTime);
        appMapper.selectPage(appPage, appLambdaQueryWrapper);
        // 3.封装返回数据
        return toAppCardVOList(appPage.getRecords());
    }

    /**
     * 通过用户id获取App列表
     *
     * @param id 用户id
     * @return app列表
     */
    @Override
    public PageResult<AppCardVO> getAppListByUserId(Long id, PageQuery pageQuery) {
        if (id == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getUserStatus().equals(UserStatus.BANNED)) {
            throw new BaseException(ExceptionConstant.USER_BANNED);
        }
        if (user.getAppAuth().equals(AppAuthEnum.HIDDEN)) {
            throw new BaseException(ExceptionConstant.APP_NO_AUTH);
        }
        // 2.分页查询
        Page<App> appPage = new Page<>(pageQuery.getCurrentPage(), UserConstant.USER_PAGE_SIZE);
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.eq(App::getUserId, id)
                .eq(App::getReviewStatus, ReviewStatusEnum.PASS.getValue())
                .orderByDesc(App::getCreateTime);
        appMapper.selectPage(appPage, appLambdaQueryWrapper);
        List<AppCardVO> appCardVOList = toAppCardVOList(appPage.getRecords());
        return new PageResult<>(appPage.getTotal(), appCardVOList);
    }

    /**
     * 通过token获取当前登录者创建的应用
     *
     * @return
     */
    @Override
    public PageResult<AppCardVO> getAppListByToken(PageQuery pageQuery) {
        // 1.参数校验
        Long id = UserBaseContext.getUser().getId();
        if (id == null) {
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        }
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getUserStatus().equals(UserStatus.BANNED)) {
            throw new BaseException(ExceptionConstant.ACCOUNT_EX);
        }
        // 2.分页查询
        Page<App> appPage = new Page<>(pageQuery.getCurrentPage(), UserConstant.USER_PAGE_SIZE);
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.eq(App::getUserId, id)
                .orderByDesc(App::getCreateTime);
        appMapper.selectPage(appPage, appLambdaQueryWrapper);
        // 3.封装返回数据
        List<AppCardVO> appCardVOList = toAppCardVOList(appPage.getRecords());
        return new PageResult<>(appPage.getTotal(), appCardVOList);
    }

    /**
     * 获取用户页推荐的应用列表
     *
     * @return
     */
    @Override
    public List<AppBrowseVO> getAppRecommendListInUserPage() {
        Set<String> recommendList = redisUtils
                .getAppBrowseTop(AppConstant.APP_RECOMMEND_NUM[0], AppConstant.APP_RECOMMEND_NUM[1]);
        if (recommendList == null || recommendList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> ids = recommendList.stream().map(Long::parseLong).toList();
        if (ids.isEmpty()) {
            return Collections.emptyList();
        }
        // 这里直接根据ids批量查询即可
        List<App> appList = appMapper.selectBatchIds(ids);
        return appList.stream().filter(app -> app.getReviewStatus().equals(ReviewStatusEnum.PASS.getValue()))
                .map(app -> BeanUtil.copyProperties(app, AppBrowseVO.class))
                .toList();
    }

    /**
     * 分页查找当前用户收藏的应用
     *
     * @param pageQuery
     * @return
     */
    @Override
    public PageResult<AppCardVO> pageQueryCollectAppOfCreateUser(PageQuery pageQuery) {
        // 1.校验参数
        if (BeanUtil.isEmpty(pageQuery)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        // 2.获取当前用户
        Long userId = UserBaseContext.getUser().getId();
        if (userId == null) {
            throw new BaseException(ErrorCode.SYSTEM_ERROR);
        }
        User user = userMapper.selectById(userId);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getUserStatus().equals(UserStatus.BANNED)) {
            throw new BaseException(ExceptionConstant.USER_BANNED);
        }
        // 3.开始分页
        LambdaQueryWrapper<UserCollect> userCollectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        Page<UserCollect> userCollectPage = new Page<>(pageQuery.getCurrentPage(), UserConstant.USER_PAGE_SIZE);
        userCollectLambdaQueryWrapper.eq(UserCollect::getUserId, userId);
        collectMapper.selectPage(userCollectPage, userCollectLambdaQueryWrapper);
        // 4.封装数据
        List<Long> appIdList = userCollectPage.getRecords().stream().map(UserCollect::getAppId).toList();
        if (appIdList.isEmpty()) {
            return new PageResult<>(userCollectPage.getTotal(), Collections.emptyList());
        }
        List<App> appList = appMapper.selectBatchIds(appIdList);
        return new PageResult<>(userCollectPage.getTotal(), toAppCardVOList(appList));
    }

    /**
     * 根据用户id分页查询他收藏的应用
     *
     * @param id
     * @param pageQuery
     * @return
     */
    @Override
    public PageResult<AppCardVO> pageQueryCollectAppById(Long id, PageQuery pageQuery) {
        if (id == null || BeanUtil.isEmpty(pageQuery)) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        User user = userMapper.selectById(id);
        if (BeanUtil.isEmpty(user)) {
            throw new BaseException(ExceptionConstant.USER_NOT_EXIST);
        }
        if (user.getUserStatus().equals(UserStatus.BANNED)) {
            throw new BaseException(ExceptionConstant.USER_BANNED);
        }
        // 3.开始分页
        LambdaQueryWrapper<UserCollect> userCollectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        Page<UserCollect> userCollectPage = new Page<>(pageQuery.getCurrentPage(), UserConstant.USER_PAGE_SIZE);
        userCollectLambdaQueryWrapper.eq(UserCollect::getUserId, id);
        collectMapper.selectPage(userCollectPage, userCollectLambdaQueryWrapper);
        // 4.封装数据
        List<Long> appIdList = userCollectPage.getRecords().stream().map(UserCollect::getAppId).toList();
        if (appIdList.isEmpty()) {
            return new PageResult<>(userCollectPage.getTotal(), Collections.emptyList());
        }
        List<App> appList = appMapper.selectBatchIds(appIdList);
        return new PageResult<>(userCollectPage.getTotal(), toAppCardVOList(appList));
    }

    /**
     * 设置应用推荐状态
     *
     * @param id
     * @param status
     * @return
     */
    @Override
    public int updateAppRecommendStatus(Long id, Integer status) {
        AppRecommendEnum enumByValue = AppRecommendEnum.getEnumByValue(status);
        if (enumByValue == null) {
            throw new WarnException(ErrorCode.PARAMS_ERROR);
        }
        LambdaQueryWrapper<App> appLambdaQueryWrapper = new LambdaQueryWrapper<>();
        appLambdaQueryWrapper.eq(App::getId, id);
        App app = appMapper.selectOne(appLambdaQueryWrapper);
        app.setRecommendFlag(enumByValue.getValue());
        return appMapper.updateById(app);
    }

    /**
     * 检查AppEditDTO参数合法性
     *
     * @param appEditDTO
     */
    private void checkEditDTO(AppEditDTO appEditDTO) {
        if (!CheckUtils.checkAppName(appEditDTO.getAppName())) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        if (!CheckUtils.checkAppDescription(appEditDTO.getAppDesc())) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        if (appEditDTO.getCategoryId() == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        if (AppScoringStrategyEnum.getEnumByValue(appEditDTO.getScoringStrategy()) == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
    }

    /**
     * 获取应用卡片VO列表
     *
     * @param appList appList
     * @return List<AppCardVO>
     */
    private List<AppCardVO> toAppCardVOList(List<App> appList) {
        // 1.如果appList为空,直接返回空集合
        if (appList.isEmpty()) {
            return Collections.emptyList();
        }
        // 2.对app对应的用户id去重
        Set<Long> userIdSet = appList.stream().map(App::getUserId).collect(Collectors.toSet());
        // 3.批量查询所有app对应用户, 以id - user方式存储
        Map<Long, List<User>> userIdUserListMap = userMapper.selectBatchIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));
        // 4.内存中封装数据
        return appList.stream().map(app -> {
            AppCardVO appCardVO = BeanUtil.copyProperties(app, AppCardVO.class);
            if (userIdUserListMap.containsKey(app.getUserId())) {
                User user = userIdUserListMap.get(app.getUserId()).get(0);
                appCardVO.setUserId(user.getId());
                appCardVO.setNickname(user.getNickname());
                appCardVO.setAvatar(user.getAvatar());
                // 后期考虑性能优化
                UserSafetyDTO currentUser = UserBaseContext.getUser();
                if (currentUser != null) {
                    Integer integer = collectMapper.selectIsCollect(app.getId(), currentUser.getId());
                    appCardVO.setCollectFlag(integer > 0);
                } else {
                    appCardVO.setCollectFlag(false);
                }
            }
            return appCardVO;
        }).toList();
    }

    /**
     * 检查appAddDTO字段合法性
     *
     * @param appAddDTO
     * @return
     */
    private boolean checkAddDTO(AppAddDTO appAddDTO) {
        if (!CheckUtils.checkAppName(appAddDTO.getAppName())) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        if (!CheckUtils.checkAppDescription(appAddDTO.getAppDesc())) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        if (appAddDTO.getCategoryId() == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        AppTypeEnum appTypeEnum = AppTypeEnum.getEnumByValue(appAddDTO.getAppType());
        if (appTypeEnum == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        AppScoringStrategyEnum scoringStrategyEnum = AppScoringStrategyEnum.getEnumByValue(appAddDTO.getScoringStrategy());
        if (scoringStrategyEnum == null) {
            throw new BaseException(ExceptionConstant.FORMAT_ERROR);
        }
        return true;
    }

    private boolean deleteAppResource(Long appId) {
        // 3.app对应题目
        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        questionLambdaQueryWrapper.eq(Question::getAppId, appId);
        // 4.app对应评分规则
        LambdaQueryWrapper<ScoringResult> resultLambdaQueryWrapper = new LambdaQueryWrapper<>();
        resultLambdaQueryWrapper.eq(ScoringResult::getAppId, appId);
        // 5.app对应答题记录
        LambdaQueryWrapper<UserAnswer> userAnswerLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userAnswerLambdaQueryWrapper.eq(UserAnswer::getAppId, appId);
        // 6.app对应收藏记录
        LambdaQueryWrapper<UserCollect> userCollectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userCollectLambdaQueryWrapper.eq(UserCollect::getAppId, appId);

        // 删除app以及更新对应资源
        appMapper.deleteById(appId);
        questionMapper.delete(questionLambdaQueryWrapper);
        scoringResultMapper.delete(resultLambdaQueryWrapper);
        userAnswerMapper.delete(userAnswerLambdaQueryWrapper);

        // 7.获取app对应所有收藏用户，修改用户收藏数量
        List<UserCollect> userCollects = collectMapper.selectList(userCollectLambdaQueryWrapper);
        if (userCollects != null && !userCollects.isEmpty()) {
            List<Long> userIds = userCollects.stream().map(UserCollect::getUserId).toList();
            List<User> users = userMapper.selectBatchIds(userIds);
            List<User> updateUserList = users.stream().peek(user -> user.setCollect(user.getCollect() - 1)).toList();
            userMapper.updateById(updateUserList);
        }
        // 删除收藏记录
        collectMapper.delete(userCollectLambdaQueryWrapper);
        // 删除今日浏览记录
        redisUtils.deleteAppBrowseById(appId);
        // 删除app对应的所有题目选项缓存
        String prefixKey = RedisConstant.APP_USER_ANSWER + appId + ":";
        redisUtils.deleteObjectFormCacheByPrefix(prefixKey);
        return true;
    }
}




